package com.meisiabc.app.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.meisiabc.app.repository.db.constant.ScheduleStatus;
import com.meisiabc.app.repository.db.entity.*;
import com.meisiabc.app.repository.db.manager.*;
import com.meisiabc.utils.DateUtil;
import com.meisiabc.utils.Verify;
import com.meisiabc.utils.math.BigDecimalUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.LocalDateTime;
import org.joda.time.format.DateTimeFormat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Slf4j
@Service
public class LessonService {
    @Autowired
    private StudentManager studentManager;
    @Autowired
    private TeacherManager teacherManager;
    @Autowired
    private PurchaseCourseManager purchaseCourseManager;
    @Autowired
    private CurriculumScheduleManager curriculumScheduleManager;
    @Autowired
    private LessonManager lessonManager;
    @Autowired
    private TrylistenmanageManager trylistenmanageManager;
    @Autowired
    private ProgressReportManager progressReportManager;
    @Autowired
    private EmailService emailService;
    @Autowired
    private WechatService wechatService;
    @Autowired
    private WechatMpSessionManager wechatMpSessionManager;


    public List<JSONObject> getLessonList(String mobile) {
        List<JSONObject> result = new ArrayList<>();
        Student student = studentManager.selectByMobile(mobile);
        if (student == null) {
            return result;
        }

        purchaseCourse(student.getStudentId(), result);
        trylistenmanage(student.getStudentId(), result);
        return result;
    }

    private void purchaseCourse(String studentId, List<JSONObject> result) {
        List<PurchaseCourse> courses = purchaseCourseManager.selectByStudentId(studentId);
        if (courses == null || courses.isEmpty()) {
            return;
        }

        for (PurchaseCourse course : courses) {
            Teacher teacher = teacherManager.selectByUniqueid(course.getTeacherId());
            String teacherName = teacher == null ? "" : teacher.getName();

            String lessonName = "";
            if (course != null && StringUtils.isNotBlank(course.getMaterial())) {
                Lesson lesson = lessonManager.selectById(course.getMaterial());
                if (lesson != null) {
                    lessonName = lesson.getNameEn();
                }
            }

            int hoursEnrolled = course.getHoursEnrolled() == null ? 0 : course.getHoursEnrolled();
            int hoursCompleted = hoursCompleted(course.getUniqueid());
            BigDecimal total_hour = BigDecimalUtils.cal(String.valueOf(hoursEnrolled)).div("60.0", 2).result();
            BigDecimal completed_hour = BigDecimalUtils.cal(String.valueOf(hoursCompleted)).div("60.0", 2).result();

            JSONObject item = new JSONObject()
                    .fluentPut("id", course.getUniqueid())
                    .fluentPut("unique_id", course.getUniqueid())
                    .fluentPut("title", lessonName)
                    .fluentPut("total_hour", total_hour)
                    .fluentPut("completed_hour", completed_hour)
                    .fluentPut("level", course.getMaterialLevel())
                    .fluentPut("type", course.getType())
                    .fluentPut("teacher", teacherName)
                    .fluentPut("purchase_time", course.getPurchaseDate());

            if (hoursEnrolled > 0) {
                item.fluentPut("hour_percent", (hoursCompleted * 100) / hoursEnrolled);
            } else {
                item.fluentPut("hour_percent", 100);
            }

            result.add(item);
        }
    }


    private void trylistenmanage(String studentId, List<JSONObject> result) {
        List<Trylistenmanage> trylistenmanages = trylistenmanageManager.selectByStudentId(studentId);
        if (trylistenmanages == null || trylistenmanages.isEmpty()) {
            return;
        }

        for (Trylistenmanage trylistenmanage : trylistenmanages) {
            Teacher teacher = teacherManager.selectByUniqueid(trylistenmanage.getTeacherId());
            String teacherName = teacher == null ? "" : teacher.getName();

            Lesson lesson = lessonManager.selectById(trylistenmanage.getCourse());
            String lessonName = "";
            if (lesson != null) {
                lessonName = lesson.getNameEn();
            }
            JSONObject bean = new JSONObject()
                    .fluentPut("id", trylistenmanage.getId())
                    .fluentPut("unique_id", trylistenmanage.getUniqueId())
                    .fluentPut("title", lessonName)
                    .fluentPut("level", trylistenmanage.getCourseLevel())
                    .fluentPut("type", trylistenmanage.getTrylistenType())
                    .fluentPut("teacher", teacherName)
                    .fluentPut("purchase_time", trylistenmanage.getAuditionDate())
                    .fluentPut("now_state", trylistenmanage.getNowState());

            double totalHour = resolveTrylistenmanageTotalHour(trylistenmanage.getHoursEnrolled());

            if ("已完成".equals(trylistenmanage.getNowState())) {
                bean.fluentPut("total_hour", totalHour)
                        .fluentPut("completed_hour", totalHour)
                        .fluentPut("hour_percent", 100);
            } else {
                bean.fluentPut("total_hour", totalHour)
                        .fluentPut("completed_hour", 0)
                        .fluentPut("hour_percent", 0);
            }
            result.add(bean);
        }
    }

    private double resolveTrylistenmanageTotalHour(int hoursEnrolled) {
        double total = hoursEnrolled * 15;
        return total / 60.0;
    }

    public JSONObject getLessonHistory(String mobile, String lessonId, String type) {
        Student student = studentManager.selectByMobile(mobile);
        if (student == null) {
            return null;
        }

        if ("新试听".equals(type) || "二次试听".equals(type)) {
            return resolveTrylistenmanageLessonHistory(lessonId, student.getStudentId());
        }

        return resolvePurchaseCourseHistory(lessonId, mobile);
    }


    private JSONObject resolveTrylistenmanageLessonHistory(String lessonId, String studentId) {
        JSONObject result = new JSONObject();

        Trylistenmanage trylistenmanage = trylistenmanageManager.getById(lessonId);
        if (!studentId.equals(trylistenmanage.getStudentId())) {
            return result;
        }

        Teacher teacher = teacherManager.selectByUniqueid(trylistenmanage.getTeacherId());
        String teacherName = teacher == null ? "" : teacher.getName();

        Lesson lesson = lessonManager.selectById(trylistenmanage.getCourse());
        String lessonName = "";
        if (lesson != null) {
            lessonName = lesson.getNameEn();
        }

        List<JSONObject> histories = new ArrayList<>();
        result.fluentPut("histories", histories)
                .fluentPut("student", new JSONObject().fluentPut("jia", 0).fluentPut("que", 0))
                .fluentPut("teacher", new JSONObject().fluentPut("jia", 0).fluentPut("que", 0))
                .fluentPut("no_lesson", 0)
                .fluentPut("id", lessonId)
                .fluentPut("unique_id", trylistenmanage.getUniqueId())
                .fluentPut("title", lessonName)
                .fluentPut("level", trylistenmanage.getCourseLevel())
                .fluentPut("type", trylistenmanage.getTrylistenType())
                .fluentPut("teacherName", teacherName)
                .fluentPut("purchase_time", trylistenmanage.getAuditionDate())
                .fluentPut("now_state", trylistenmanage.getNowState());

        double totalHour = resolveTrylistenmanageTotalHour(trylistenmanage.getHoursEnrolled());

        if ("已完成".equals(trylistenmanage.getNowState())) {
            result.fluentPut("total_hour", totalHour)
                    .fluentPut("completed_hour", totalHour)
                    .fluentPut("hour_percent", 100);
        } else {
            result.fluentPut("total_hour", totalHour)
                    .fluentPut("completed_hour", 0)
                    .fluentPut("hour_percent", 0);
        }

        return result;
    }

    private JSONObject resolvePurchaseCourseHistory(String lessonId, String mobile) {
        JSONObject result = new JSONObject();
        PurchaseCourse course = getPurchaseCourse(mobile, lessonId);
        if (course == null) {
            return null;
        }

        List<CurriculumSchedule> curriculumSchedules = curriculumScheduleManager.selectByPurchaseCourseId(course.getUniqueid());


        curriculumSchedules.sort(new Comparator<CurriculumSchedule>() {
            @Override
            public int compare(CurriculumSchedule o1, CurriculumSchedule o2) {
                if (o1.getState() != null && o2.getState() != null) {
                    return o2.getId() - o1.getId();
                }

                if (o1.getState() == null) {
                    if (o2.getState() != null) {
                        return 1;
                    }
                    return o1.getId() - o2.getId();
                }

                return -1;
            }
        });

        List<JSONObject> histories = new ArrayList<>();
        int student_jia = 0;
        int student_que = 0;
        int teacher_jia = 0;
        int teacher_que = 0;
        int wuke = 0;
        for (CurriculumSchedule schedule : curriculumSchedules) {
            if (schedule.getState() == null || schedule.getState() == ScheduleStatus.S0.getCode() || schedule.getState() == ScheduleStatus.S6.getCode()) {
                continue;
            }

            histories.add(new JSONObject()
                    .fluentPut("class_date", new DateTime(schedule.getClassDate()).toString("yyyy-MM-dd"))
                    .fluentPut("class_time", schedule.getClassTime())
                    .fluentPut("class_time_end", schedule.getClassTimeEnd())
                    .fluentPut("class_week", "星期" + resolveWeekName(schedule.getClassWeek()))
                    .fluentPut("class_length", schedule.getClassLength() + "分钟")
                    .fluentPut("state", schedule.getState())
                    .fluentPut("state_name", ScheduleStatus.toDesc(schedule.getState()))
                    .fluentPut("performance", schedule.getPerformance())
                    .fluentPut("homework", schedule.getHomework())
                    .fluentPut("content_next_lecture", schedule.getContentNextLecture())
            );


            if (schedule.getState() == ScheduleStatus.S2.getCode()) {
                student_jia++;
            } else if (schedule.getState() == ScheduleStatus.S3.getCode()) {
                student_que++;
            } else if (schedule.getState() == ScheduleStatus.S4.getCode()) {
                teacher_jia++;
            } else if (schedule.getState() == ScheduleStatus.S5.getCode()) {
                teacher_que++;
            } else if (schedule.getState() == ScheduleStatus.S1.getCode()) {
                wuke++;
            }
        }

        Teacher teacher = teacherManager.selectByUniqueid(course.getTeacherId());
        String teacherName = teacher == null ? "" : teacher.getName();

        Lesson lesson = lessonManager.selectById(course.getMaterial());
        String lessonName = "";
        if (lesson != null) {
            lessonName = lesson.getNameEn();
        }

        int hoursEnrolled = course.getHoursEnrolled() == null ? 0 : course.getHoursEnrolled();
        int hoursCompleted = hoursCompleted(course.getUniqueid());
        BigDecimal total_hour = BigDecimalUtils.cal(String.valueOf(hoursEnrolled)).div("60.0", 2).result();
        BigDecimal completed_hour = BigDecimalUtils.cal(String.valueOf(hoursCompleted)).div("60.0", 2).result();

        result.fluentPut("histories", histories);
        result.fluentPut("student", new JSONObject().fluentPut("jia", student_jia).fluentPut("que", student_que));
        result.fluentPut("teacher", new JSONObject().fluentPut("jia", teacher_jia).fluentPut("que", teacher_que));
        result.fluentPut("no_lesson", wuke);
        result.fluentPut("id", course.getUniqueid())
                .fluentPut("unique_id", course.getUniqueid())
                .fluentPut("title", lessonName)
                .fluentPut("total_hour", total_hour)
                .fluentPut("completed_hour", completed_hour)
                .fluentPut("level", course.getMaterialLevel())
                .fluentPut("type", course.getType())
                .fluentPut("teacherName", teacherName)
                .fluentPut("purchase_time", course.getPurchaseDate());

        if (hoursEnrolled > 0) {
            result.fluentPut("hour_percent", (hoursCompleted * 100) / hoursEnrolled);
        } else {
            result.fluentPut("hour_percent", 100);
        }

        return result;
    }


    private int hoursCompleted(String courseId) {
        int result = 0;
        List<CurriculumSchedule> schedules = curriculumScheduleManager.list(new QueryWrapper<CurriculumSchedule>().eq("purchase_course_id", courseId).in("state", Arrays.asList(String.valueOf(ScheduleStatus.S7.getCode()), String.valueOf(ScheduleStatus.S3.getCode()))));
        for (CurriculumSchedule schedule : schedules) {
            result += schedule.getClassLength();
        }

        return result;
    }

    private String resolveWeekName(int i) {
        if (i == 1) {
            return "一";
        }

        if (i == 2) {
            return "二";
        }

        if (i == 3) {
            return "三";
        }

        if (i == 4) {
            return "四";
        }

        if (i == 5) {
            return "五";
        }

        if (i == 6) {
            return "六";
        }

        if (i == 7) {
            return "日";
        }

        return String.valueOf(i);
    }

    public JSONObject report(String mobile, String lessonId, String type) {
        Student student = studentManager.selectByMobile(mobile);
        if (student == null) {
            return null;
        }

        if ("新试听".equals(type) || "二次试听".equals(type)) {
            return resolveTrylistenmanageLessonReport(lessonId, student.getStudentId());
        }

        return resolvePurchaseCourseReport(lessonId, mobile);
    }


    private JSONObject resolveTrylistenmanageLessonReport(String lessonId, String studentId) {
        JSONObject result = new JSONObject();
        Trylistenmanage trylistenmanage = trylistenmanageManager.getById(lessonId);
        if (!studentId.equals(trylistenmanage.getStudentId())) {
            return result;
        }

        Map resultMap = new LinkedHashMap();
        resultMap.put("level", trylistenmanage.getLevel());
        resultMap.put("speaking", trylistenmanage.getSparking());
        resultMap.put("diction", trylistenmanage.getDiction());
        resultMap.put("grammar", trylistenmanage.getGrammar());
        resultMap.put("sentence ", trylistenmanage.getSentence());
        resultMap.put("listening", trylistenmanage.getListening());
        resultMap.put("reading", trylistenmanage.getReading());
        resultMap.put("comprehension", trylistenmanage.getComprehension());
        resultMap.put("generalRecommendation", trylistenmanage.getGeneral());
        resultMap.put("materialRecommendation", trylistenmanage.getMaterial());
      return new JSONObject(resultMap);

//        return result.fluentPut("level", trylistenmanage.getLevel())
//                .fluentPut("speaking", trylistenmanage.getSparking())
//                .fluentPut("diction", trylistenmanage.getDiction())
//                .fluentPut("grammar", trylistenmanage.getGrammar())
//                .fluentPut("sentence ", trylistenmanage.getSentence())
//                .fluentPut("listening", trylistenmanage.getListening())
//                .fluentPut("reading", trylistenmanage.getReading())
//                .fluentPut("comprehension", trylistenmanage.getComprehension())
//                .fluentPut("generalRecommendation", trylistenmanage.getGeneral())
//                .fluentPut("materialRecommendation", trylistenmanage.getMaterial());
    }

    private JSONObject resolvePurchaseCourseReport(String lessonId, String mobile) {
        JSONObject result = new JSONObject();
        PurchaseCourse course = getPurchaseCourse(mobile, lessonId);
        if (course == null) {
            return result;
        }

        ProgressReport progressReport = progressReportManager.getOne(new QueryWrapper<ProgressReport>().eq("purchase_course_id", course.getId()));
        if (progressReport == null) {
            return result;
        }

        Map resultMap = new LinkedHashMap();
        resultMap.put("effortParticipation", progressReport.getEffortParticipation());
        resultMap.put("behavior", progressReport.getBehavior());
        resultMap.put("vocabulary", progressReport.getVocabulary());
        resultMap.put("grammar", progressReport.getGrammar());
        resultMap.put("sentenceConstruction", progressReport.getSentenceConstruction());
        resultMap.put("pronunciation", progressReport.getPronunciation());
        resultMap.put("reading", progressReport.getReading());
        return new JSONObject(resultMap);

//        return result.fluentPut("effortParticipation", progressReport.getEffortParticipation())
//                .fluentPut("behavior", progressReport.getBehavior())
//                .fluentPut("vocabulary", progressReport.getVocabulary())
//                .fluentPut("grammar", progressReport.getGrammar())
//                .fluentPut("sentenceConstruction", progressReport.getSentenceConstruction())
//                .fluentPut("pronunciation", progressReport.getPronunciation())
//                .fluentPut("reading", progressReport.getReading());
    }


    public Collection<JSONObject> getLessonCalendar(String mobile, String lessonId, LocalDate startDate) {
        PurchaseCourse course = getPurchaseCourse(mobile, lessonId);
        if (course == null) {
            return null;
        }

        LocalDate endDate = startDate.plusMonths(1);
        List<CurriculumSchedule> curriculumSchedules = curriculumScheduleManager.selectByPurchaseCourseIdPeriod(course.getUniqueid(), startDate.format(DateTimeFormatter.ISO_LOCAL_DATE), endDate.format(DateTimeFormatter.ISO_LOCAL_DATE));
        if (curriculumSchedules == null || curriculumSchedules.isEmpty()) {
            return null;
        }

        Map<String, JSONObject> calendar = new HashMap<>();
        for (CurriculumSchedule schedule : curriculumSchedules) {
            String class_date = new DateTime(schedule.getClassDate()).toString("yyyy-MM-dd");

            JSONObject dayJson = calendar.get(class_date);
            if (dayJson == null) {
                dayJson = new JSONObject().fluentPut("date", class_date);
                calendar.put(class_date, dayJson);
            }

            JSONArray courseList = dayJson.getJSONArray("courseList");
            if (courseList == null) {
                courseList = new JSONArray();
                dayJson.put("courseList", courseList);
            }

            Teacher teacher = teacherManager.selectByUniqueid(schedule.getTeacherId());
            String teacherName = teacher == null ? "" : teacher.getName();

            courseList.add(new JSONObject()
                    .fluentPut("schedule_id", schedule.getId())
                    .fluentPut("class_time", schedule.getClassTime())
                    .fluentPut("class_time_end", schedule.getClassTimeEnd())
                    .fluentPut("state", schedule.getState())
                    .fluentPut("state_name", ScheduleStatus.toDesc(schedule.getState()))
                    .fluentPut("teacher_name", teacherName)
            );
        }

        return calendar.values();
    }

    private PurchaseCourse getPurchaseCourse(String mobile, String lessonId) {
        Student student = studentManager.selectByMobile(mobile);
        if (student == null) {
            return null;
        }

        PurchaseCourse course = purchaseCourseManager.selectByIdAndStudentId(lessonId, student.getStudentId());
        if (course != null) {
            return course;
        }

        return null;
    }

    public void leave(String mobile, int id, DateTime now) {
        Student student = studentManager.selectByMobile(mobile);
        Verify.notNull(student, "学生不存在");

        CurriculumSchedule schedule = curriculumScheduleManager.getById(id);
        Verify.notNull(schedule, "该课程不存在");
        Verify.isTrue(student.getStudentId().equals(schedule.getStudentId()), "该课程不是你的，不能请假");
        Verify.isTrue(schedule.getState() == null || schedule.getState() == ScheduleStatus.S0.getCode() || schedule.getState() == ScheduleStatus.S6.getCode(), "该课程状态不准许请假");

        DateTime scheduleDay = new DateTime(schedule.getClassDate());
        String[] hourMin = schedule.getClassTime().split(":");
        DateTime scheduledate = new DateTime(scheduleDay.getYear(), scheduleDay.getMonthOfYear(), scheduleDay.getDayOfMonth(), Integer.valueOf(hourMin[0]), Integer.valueOf(hourMin[1]), 0);

        DateTime start = now.plusHours(6);
        Verify.isTrue(start.isBefore(scheduledate), "Sorry，还有6个小时就要上课了，不能请假了");

        DateTime end = now.plusWeeks(2);
        Verify.isTrue(end.isAfter(scheduledate), "抱歉，只能提交两周内课程的请假申请");

        curriculumScheduleManager.updateById(CurriculumSchedule.builder().id(id).state(ScheduleStatus.S2.getCode()).stateName(ScheduleStatus.S2.getDesc()).build());

        CurriculumSchedule tailSchedule = curriculumScheduleManager.getTail(schedule.getPurchaseCourseId());
        DateTime classDate = new DateTime(tailSchedule.getClassDate());
        DateTime newClassDate = null;
        if (classDate.getDayOfWeek() == schedule.getClassWeek()) {
            newClassDate = classDate.plusWeeks(1);
        } else {
            int period = classDate.getDayOfWeek() - schedule.getClassWeek();
            if (period < 0) {
                newClassDate = classDate.plusDays(-period);
            } else {
                newClassDate = classDate.plusDays(period);
            }
        }

        schedule.setClassDate(newClassDate.toDate());
        schedule.setId(null);
        schedule.setState(ScheduleStatus.S0.getCode());
        curriculumScheduleManager.save(schedule);

        Teacher teacher = teacherManager.selectByUniqueid(schedule.getTeacherId());
        Verify.notNull(teacher, "教师不存在");

        if (StringUtils.isBlank(teacher.getEmail())) {
            log.info("teacher email is blank.[teacher={}]", teacher.getId());
            return;
        }
        emailService.sendEmail(teacher.getEmail(), teacher.getName(), student.getEnName(), student.getZoomId(), scheduledate, schedule.getClassTimeEnd(), now);

        try {
            if (student != null && StringUtils.isNotBlank(student.getPhone())) {
                WechatMpSession wechatMpSession = wechatMpSessionManager.getOne(new QueryWrapper<WechatMpSession>().eq("mobile", student.getPhone()));

                Lesson lesson = lessonManager.selectById(schedule.getMaterial());
                if (wechatMpSession != null && StringUtils.isNotBlank(wechatMpSession.getOpenid()) && lesson != null && StringUtils.isNotBlank(lesson.getNameZh())) {

                    String date = DateUtil.defalultFomrt(schedule.getClassDate(), "yyyy-MM-dd");
                    String leaveDate = date + " " + schedule.getClassTime() + "-" + schedule.getClassTimeEnd();
                    wechatService.smsStudentLeave(wechatMpSession.getOpenid(), student.getEnName(), lesson.getNameZh(), leaveDate);
                } else {
                    log.info("学生请假通知未发送，原因：信息不全，mobile:{}", student.getPhone());
                }
            }
        } catch (Exception e) {
            log.error("学生请假异常", e);
        }
    }


    public int count(String material) {
        return purchaseCourseManager.count(new QueryWrapper<PurchaseCourse>().eq("material", material));
    }


}
